#include "FileHelper.h"
#include "CommonUtil.h"
#include <shellapi.h>
#include <Shlobj.h>
static const char kEndChar = '\0';
static const char kFilePathSeparators[] = "\\/";
static const char kFilePathCurrentDirectory[] = ".";
static const char kFilePathParentDirectory[] = "..";
static const char kFilePathExtensionSeparator = '.';

static bool IsFilePathSeparator(const char separator) {
    if (separator == kEndChar) {
        return false;
    }
    
    size_t len = sizeof(kFilePathSeparators) / sizeof(char);
    for (size_t i = 0; i < len; i++) {
        if (separator == kFilePathSeparators[i]) {
            return true;
        }
    }
    
    return false;
}

static bool IsFilePathSeparator(const std::string &separator) {
    if (separator.empty()) {
        return false;
    }
    char c = separator[0];
    return IsFilePathSeparator(c);
}

static bool FilePathApartDirectory(const std::string &filepath_in, std::string &directory_out) {
    size_t index = filepath_in.size() - 1;
    if (index <= 0 || filepath_in.size() == 0) {
        return false;
    }
    for (; index != 0; index--) {
        if (IsFilePathSeparator(filepath_in[index])) {
            if (index == filepath_in.size() - 1) {
                directory_out = filepath_in;
            } else {
                directory_out = filepath_in.substr(0, index + 1);
            }
            return true;
        }
    }
    return false;
}

bool CreateDirectoryRecursively(const TCHAR *full_dir) {
    HRESULT result = ::SHCreateDirectoryEx(NULL, full_dir, nullptr);
    if (result == ERROR_SUCCESS || result == ERROR_FILE_EXISTS || result == ERROR_ALREADY_EXISTS) {
        return true;
    }
    return false;
}

bool XFileHelper::WriteFile(const std::string &filePathUtf8, const std::string &dataUtf8) {
    std::string module_directory;
    if (!FilePathApartDirectory(filePathUtf8, module_directory)) {
        return false;
    }
    
    auto wDir = CommonUtil::FromUTF8(module_directory.c_str());
    DWORD attributes = ::GetFileAttributes(wDir.c_str());
    FILE_ATTRIBUTE_DIRECTORY;
    if (attributes == INVALID_FILE_ATTRIBUTES || !(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
        CreateDirectoryRecursively(wDir.c_str());
    }
    
    std::string ret;
    FILE *pFile = nullptr;
    
    auto fileNameW = CommonUtil::FromUTF8(filePathUtf8.c_str());
    
    _wfopen_s(&pFile, fileNameW.c_str(), L"wb+");
    if (pFile != nullptr) {
        fwrite(dataUtf8.data(), 1, dataUtf8.size(), pFile);
        fclose(pFile);
        pFile = nullptr;
        return true;
    }
    
    return false;
}

std::string XFileHelper::ReadFile(const std::string &filePathUtf8) {
    auto fileNameW = CommonUtil::FromUTF8(filePathUtf8.c_str());
    
    std::string ret;
    FILE *pFile = nullptr;
    _wfopen_s(&pFile, fileNameW.c_str(), L"rb");
    
    if (pFile != nullptr) {
        char buffer[8192] = { 0 };
        int nRead = 0;
        do {
            nRead = fread(buffer, 1, 8192, pFile);
            ret.append(buffer, nRead);
        } while (nRead > 0);
        
        fclose(pFile);
        pFile = nullptr;
    }
    
    return ret;
}
